package simpledb.optimizer;

import simpledb.execution.Predicate;

/**
 * LogicalJoinNode 表示在逻辑查询计划中两个表之间的连接操作所需的状态信息。
 * 它记录了参与连接的两个表（别名）、连接字段以及连接谓词等关键信息，
 * 是优化器在进行连接顺序选择时的重要数据结构。
 */
public class LogicalJoinNode {

    /**
     * 第一个要连接的表（可以为 null）。
     * 使用的是表的别名，如果没有指定别名，则使用真实的表名。
     */
    public String       t1Alias;

    /**
     * 第二个要连接的表（可以为 null）。
     * 同样使用表的别名，或者真实表名。
     */
    public String       t2Alias;

    /**
     * 在第一个表中用于连接的字段名称（纯字段名，不带表名前缀）。
     */
    public String       f1PureName;

    /**
     * 带有表别名限定的字段1名称，格式为 "表别名.字段名"。
     */
    public String       f1QuantifiedName;

    /**
     * 在第二个表中用于连接的字段名称（纯字段名，不带表名前缀）。
     */
    public String       f2PureName;

    /**
     * 带有表别名限定的字段2名称，格式为 "表别名.字段名"。
     */
    public String       f2QuantifiedName;

    /**
     * 连接所使用的谓词操作符（如 =, >, < 等）
     */
    public Predicate.Op p;

    // 默认构造函数
    public LogicalJoinNode() {
    }

    /**
     * 构造函数：创建一个表示两个表之间连接的节点对象。
     *
     * @param table1 第一张表的别名或真实名称
     * @param table2 第二张表的别名或真实名称
     * @param joinField1 第一张表中的连接字段（可能带有表名前缀）
     * @param joinField2 第二张表中的连接字段（可能带有表名前缀）
     * @param pred 谓词操作符
     */
    public LogicalJoinNode(String table1, String table2, String joinField1, String joinField2, Predicate.Op pred) {
        t1Alias = table1;
        t2Alias = table2;

        // 解析第一个字段的纯字段名（去掉前缀）
        String[] tmps = joinField1.split("[.]");
        if (tmps.length > 1)
            f1PureName = tmps[tmps.length - 1];
        else
            f1PureName = joinField1;

        // 解析第二个字段的纯字段名（去掉前缀）
        tmps = joinField2.split("[.]");
        if (tmps.length > 1)
            f2PureName = tmps[tmps.length - 1];
        else
            f2PureName = joinField2;

        p = pred; // 设置连接谓词

        // 构建限定字段名（别名 + 字段名）
        this.f1QuantifiedName = t1Alias + "." + this.f1PureName;
        this.f2QuantifiedName = t2Alias + "." + this.f2PureName;
    }

    /**
     * 返回一个新的 LogicalJoinNode 对象，其中交换了内外表（即交换 t1 和 t2 的位置）。
     * 同时也反转谓词方向（例如将 > 变成 <）以保持语义一致性。
     *
     * @return 交换内外表后的新的连接节点
     */
    public LogicalJoinNode swapInnerOuter() {
        Predicate.Op newp;
        if (p == Predicate.Op.GREATER_THAN)
            newp = Predicate.Op.LESS_THAN;
        else if (p == Predicate.Op.GREATER_THAN_OR_EQ)
            newp = Predicate.Op.LESS_THAN_OR_EQ;
        else if (p == Predicate.Op.LESS_THAN)
            newp = Predicate.Op.GREATER_THAN;
        else if (p == Predicate.Op.LESS_THAN_OR_EQ)
            newp = Predicate.Op.GREATER_THAN_OR_EQ;
        else
            newp = p;

        return new LogicalJoinNode(t2Alias, t1Alias, f2PureName, f1PureName, newp);
    }

    /**
     * 判断两个 LogicalJoinNode 是否相等。
     * 只要两者的两个表名相同且顺序互换也算相等。
     */
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof LogicalJoinNode))
            return false;
        LogicalJoinNode j2 = (LogicalJoinNode) o;
        return (j2.t1Alias.equals(t1Alias) || j2.t1Alias.equals(t2Alias))
               && (j2.t2Alias.equals(t1Alias) || j2.t2Alias.equals(t2Alias));
    }

    /**
     * 返回该连接节点的字符串表示。
     */
    @Override
    public String toString() {
        return t1Alias + ":" + t2Alias; // 格式为 "表1:表2"
    }

    /**
     * 返回该对象的哈希码。
     */
    @Override
    public int hashCode() {
        return t1Alias.hashCode() + t2Alias.hashCode() + f1PureName.hashCode() + f2PureName.hashCode();
    }
}
